//包的定义
package com.example.ljy.kotlin001
//包的导入
import java.math.BigDecimal
//如果出现名字冲突，可以使⽤ as 关键字在本地重命名冲突项来消歧义：
// Message 可访问
import android.os.Message
// NotifiMessage 代表“android.app.Notification.MessagingStyle.Message”
import android.app.Notification.MessagingStyle.Message as NotifiMessage

//程序入口函数
fun main() {
    Test001().init()
}

/**
 * Created by ljy on 2017/11/30.
 *
 * 本类介绍kotlin的基本语法
 * 在 Kotlin 中，所有东西都是对象
 */
class Test001 {


    fun init() {
        val m: Message
        val m2: NotifiMessage
        /**
         * 0. 注释
         */

        //注释：与 Java 不同, Kotlin 中的块注释允许嵌套
        // 这是一个单行注释
        /* 这是一个
        多行的 /*abc*/
        块注释。 */

        /**
         * 1. 变量与常量：
         */

        // - 0.声明：var/val关键字 变量名 ：变量类型 ，类型也可以省略
        //且应省略分号
        var aaa: Int=0;
        val bbb =1
        // - 1.可变变量定义：var 关键字
        var x = 5        // 系统自动推断变量类型为Int
        x += 1           // 变量可修改

        // - 2.不可变变量定义：val 关键字，只能赋值一次的变量
        // (类似Java中final修饰的变量)
        //优先使⽤不可变数据
        val a: Int = 0
        val b = 1       // 系统自动推断变量类型为Int
        val c: Int      // 如果不在声明时初始化则必须提供变量类型
        c = 2

        //数字:Byte,Short,Int,Long,Float,Double

        //十进制:
        var num1=123
        //十六进制:
        var num2=0x2f
        //二进制:
        var num3=0b00001011
        //不支持八进制

//        可以使⽤下划线使数字常量更易读：
        val oneMillion = 1_000_000

        //与⼀些其他语⾔不同，Kotlin 中的数字没有隐式拓宽转换。
        // 例如，具有 Double 参数的函数只能对 Double
        //值调⽤，⽽不能对 Float 、 Int 或者其他数字值调⽤
        fun printDouble(d: Double) {
            println(d)
        }

        val n1 = 1
        val n2 = 1.1
        val n3 = 1.1f
        printDouble(n2)
//        printDouble(n1)//错误：类型不匹配
//        printDouble(n3)//错误：类型不匹配

        fun testEquals() {
            val a: Int = 100
            val boxedA: Int? = a
            val anotherBoxedA: Int? = a
            val b: Int = 10000
            val boxedB: Int? = b
            val anotherBoxedB: Int? = b
            //数字装箱不⼀定保留同⼀性:
            //===类似于equals
            println(boxedA === anotherBoxedA) // true
            println(boxedB === anotherBoxedB) // false
            //保留了相等性:
            println(b == b) // true
            println(boxedB == anotherBoxedB) // true
            //显式转换
            // 假想的代码，实际上并不能编译：(较⼩类型并不是较⼤类型的⼦类型)
            val a1: Int? = 1 // ⼀个装箱的 Int (java.lang.Integer)
//            val b1: Long? = a1 // 隐式转换产⽣⼀个装箱的 Long (java.lang.Long)
//            print(b1 == a1) // 惊！这将输出“false”鉴于 Long 的 equals() 会检测另⼀个是否也为 Long
            //可以显式转换来拓宽数字
            val b1: Long? = a1?.toLong()
            println(b1?.equals(a1) ?: (a1 == null))
            //整数间的除法总是返回整数
            val x1 = 5 / 2
            println("x1 == 2:${x1 == 2}")
            //如需返回浮点类型，请将其中的⼀个参数显式转换为浮点类型
            val x2 = 5 / 2.toDouble()
            println("x2 == 2.5:${x2 == 2.5}")
            val x3 = 5.toDouble() / 2
            println("x3 == 2.5:${x3 == 2.5}")
            //位运算:对于位运算，没有特殊字符来表⽰，⽽只可⽤中缀⽅式调⽤具名函数
            val x = (1 shl 2) and 0x000FF000
            //完整的位运算列表（只⽤于 Int 与 Long）：
            //shl(bits) ‒ 有符号左移
            //shr(bits) ‒ 有符号右移
            //ushr(bits) ‒ ⽆符号右移
            //and(bits) ‒ 位与
            //or(bits) ‒ 位或
            //xor(bits) ‒ 位异或
            //inv() ‒ 位⾮


            //NaN 与其⾃⾝相等
            println("Float.NaN== Float.NaN:${Float.NaN == Float.NaN}")
            println("Float.NaN=== Float.NaN:${Float.NaN === Float.NaN}")
            println("Float.NaN.equals( Float.NaN):${Float.NaN.equals(Float.NaN)}")
            println("Float.NaN - Float.POSITIVE_INFINITY: ${Float.NaN - Float.POSITIVE_INFINITY}")
            //-0.0 ⼩于 0.0
            println("-0.0 ⼩于 0.0:${-0.0 < 0.0}")

            //数组:
            //数组在 Kotlin 中使⽤ Array 类来表⽰，它定义了 get 与 set 函数（按照运算符重载约定这会转变为 []）以及
            //size 属性，以及⼀些其他有⽤的成员函数
            //使⽤库函数 arrayOf() 来创建⼀个数组并传递元素值给它，这样 arrayOf(1, 2, 3) 创建了 array
            //[1, 2, 3] 。 或者，库函数 arrayOfNulls() 可以⽤于创建⼀个指定⼤⼩的、所有元素都为空的数组
            //另⼀个选项是⽤接受数组⼤⼩以及⼀个函数参数的 Array 构造函数，⽤作参数的函数能够返回给定索引的每个元素 初始值：
            // 创建⼀个 Array<String> 初始化为 ["0", "1", "4", "9", "16"]
            val asc = Array(5) { i -> (i * i).toString() }
            asc.forEach { println(it) }
            //原⽣类型数组: Kotlin 也有⽆装箱开销的专⻔的类来表⽰原⽣类型数组: ByteArray 、 ShortArray 、IntArray 等等。这些类与
            //Array 并没有继承关系，但是它们有同样的⽅法属性集。它们也都有相应的⼯⼚⽅法
            val aar: IntArray = intArrayOf(1, 2, 3)
            aar[0] = aar[1] + aar[2]
            // ⼤⼩为 5、值为 [0, 0, 0, 0, 0] 的整型数组
            val arr1 = IntArray(5)
            // 例如：⽤常量初始化数组中的值
            // ⼤⼩为 5、值为 [42, 42, 42, 42, 42] 的整型数组
            val arr2 = IntArray(5) { 42 }
            // 例如：使⽤ lambda 表达式初始化数组中的值
            // ⼤⼩为 5、值为 [0, 1, 2, 3, 4] 的整型数组（值初始化为其索引值）
            var arr3 = IntArray(5) { it * 1 }
            //⽆符号整型:
            //kotlin.UByte : ⽆符号 8 ⽐特整数，范围是 0 到 255
            //kotlin.UShort : ⽆符号 16 ⽐特整数，范围是 0 到 65535
            //kotlin.UInt : ⽆符号 32 ⽐特整数，范围是 0 到 2^32 - 1
            //kotlin.ULong : ⽆符号 64 ⽐特整数，范围是 0 到 2^64 - 1

            //kotlin.UByteArray : ⽆符号字节数组
            //kotlin.UShortArray : ⽆符号短整型数组
            //kotlin.UIntArray : ⽆符号整型数组
            //kotlin.ULongArray : ⽆符号⻓整型数组
            //与有符号整型数组⼀样，它们提供了类似于 Array 类的 API ⽽没有装箱开销

            //字⾯值:为使⽆符号整型更易于使⽤，Kotlin 提供了⽤后缀标记整型字⾯值来表⽰指定⽆符号类型（类似于 Float/Long）
            // 后缀 u 与 U 将字⾯值标记为⽆符号
//            val b: UByte = 1u // UByte，已提供预期类型
//            val s: UShort = 1u // UShort，已提供预期类型
//            val l: ULong = 1u // ULong，已提供预期类型
//            val a1 = 42u // UInt：未提供预期类型，常量适于 UInt
//            val a2 = 0xFFFF_FFFF_FFFFu // ULong：未提供预期类型，常量不适于 UInt
//            //后缀 uL 与 UL 显式将字⾯值标记为⽆符号⻓整型。
//            val a = 1UL // ULong，即使未提供预期类型并且常量适于 UInt
        }

        testEquals()

        /**
         * 2. 函数
         * Kotlin函数支持函数嵌套，即在函数体内还可以嵌套局部函数
         */

        /*
         * - 1. 定义一个普通的函数
         * 1。函数定义：使用关键字 fun
         * 2。参数格式为：参数 : 类型 ,参数 : 类型，...
         * 3。返回值类型：在（）后面加 : 类型
         */
        fun testFun(n: Int, str: String): Boolean {
            println("n=$n")
            println("str=$str")
            return true
        }

        val bool = testFun(10, "abc")
        println("bool=$bool")

        /*
         * - 2.表达式作为函数体，返回类型自动推断：
         */
        fun isZero(i: Int) = i == 0//表达式函数

        val isZero = isZero(1)
        println("isZero:$isZero")

        /*
         * - 3.无返回值的函数(类似Java中的void)
         * Unit类型，可以省略(应该省略)
         */
        fun noReturn(): Unit {
            println("no return")
        }

        fun noReturn2() {
            println("no return2")
        }
        noReturn()
        noReturn2()

        /*
         *  - 4.可变长参数函数：
         *  变长参数可以用 vararg 关键字进行标识
         *  注意混用时的调用：
         *  可变长参数与普通参数混用, 注意普通参数要用key=value，以和可变长参数区分
         */
        fun printNums(vararg numArr: Int, userName: String?) {
            //上面str: String?中的？表示可为空
            for (n in numArr) {
                println("numArr-->$n")
            }
            if (userName != null)//null检测
                println("userName--->$userName")
        }
        printNums(1, 2, 3, 4, 5, userName = "ljy")

        /*
         * - 5. lambda(匿名函数)
         * 在lambda表达式中, 大括号左右要加空格，分隔参数与代码体的箭头左右也要加空格
         * lambda表达应尽可能不要写在圆括号中
         * 在非嵌套的短lambda表达式中，最好使用约定俗成的默认参数 it 来替代显式声明参数名
         * 在嵌套的有参数的lambda表达式中，参数应该总是显式声明
         */
        val sumLambda: (Int, Int) -> Int = { x, y -> x + y }
        println("1+2=" + sumLambda(1, 2))
        /*
         * - 6. 函数的默认参数(给参数添加默认值)
         */
        fun foo(a: Int = 0, b: String = "") {
            println("a=$a,b=$b")
        }
        foo()
        foo(10)
        foo(a = 101)
        foo(b = "abc")
        foo(101, "abc")
        //优先声明带有默认参数的函数⽽不是声明重载函数
        // 不良
        fun foo1(a: String) { /*……*/
        }

        fun foo1() = foo1("a")

        // 良好
        fun foo2(a: String = "a") { /*……*/
        }

        /*
         * - 7.单表达式函数
         * 对于由单个表达式构成的函数体，优先使⽤表达式形式。
         */
        fun theAnswer() = 24

        //等价于:
        fun theAnswer2(): Int {
            return 24
        }

        /**
         * 3. 字符串模版
         * 优先使⽤字符串模板⽽不是字符串拼接
         * 优先使⽤多⾏字符串⽽不是将 \n 转义序列嵌⼊到常规字符串字⾯值中
         */

        //- 1.模版中的简单名称(省略花括号)
        var num = 101
        val s1 = "num is $num"
        println(s1)
        //- 2.模版中的任意表达式
        num = 102
        val s2 = "${s1.replace("is", "was")},but now is $num"
        println(s2)
        //如需在多⾏字符串中维护缩进，
        // 当⽣成的字符串不需要任何内部缩进时使⽤ trimIndent，
        // ⽽需要内部缩进时使⽤trimMargin ：
        val a1 =
            """
                Foo
                Bar
            """.trimIndent()
        println("a1:\n$a1")

        val a2 = """if(a > 1) {
                |   return a
                |}""".trimMargin()
        println("a2:\n$a2")

        // 字符串的元素⸺字符可以使⽤索引运算符访问
        for (c in s1) {
            println(c)
        }
        //字符串字⾯值:(两种)
        //1. 转义字符串: 可以有转义字符
        val s = "Hello, world!\n"
        //2. 原始字符串: 使⽤三个引号（ """ ）分界符括起来
        val text = """
            for (c in "foo")
            print(c)
        """
        /**
         * 4. 条件表达式和循环表达式
         */

        //- 1.if判断
        if (num > 0) {
            println(num)
        } else {
            println("num < 0")
        }
        //
        val data = mapOf("name" to "ljy", "email" to null)
        // if null ?:
        data["name"] ?: println("name is null")
        data["email"] ?: println("email is null")
        // if not null 缩写 ?.
        println("name len = ${data["name"]?.length}")
        println("email len = ${data["email"]?.length}")
        // if not null and else 缩写 ?. :
        println(data["name"]?.length ?: "empty")
        println(data["email"]?.length ?: "empty")


        /*
         * - 2.使用if作为表达式
         * 并结合单表达式函数使用
         * 在 Kotlin 中，if是⼀个表达式，即它会返回⼀个值。 因此就不需要三元运算符（条件 ? 然后 : 否则），
         * 因为普通的 if 就能胜任这个⻆⾊。
         */
        fun maxOf(a: Int, b: Int) = if (a > b) a else b

        num = maxOf(a, b)

        //if 的分⽀可以是代码块，最后的表达式作为该块的值：
        //如果你使⽤ if 作为表达式⽽不是语句（例如：返回它的值或者把它赋给变量），该表达式需要有 else 分⽀
        val max1 = if (a > b) {
            print("Choose a")
            a
        } else {
            print("Choose b")
            b
        }

        /*
         * - 3.when表达式做函数返回值
         * 并结合单表达式函数使用
         */
        fun describe(obj: Any) =
            when (obj) {
                1 -> "one"
                "Hello" -> "greeting"
                //如果很多分⽀需要⽤相同的⽅式处理,可以把多个分⽀条件放在⼀起，⽤逗号分隔
                0, 2 -> "obj == 0 or obj == 2"
                //在不在⼀个区间或集合中
                in 1..10 -> "obj is in the range"
                is Long -> "Long"
                !is String -> "not a string"
                else -> "Unknown"
            }

        println("-->${describe(1)}")
        println("-->${describe("Hello")}")
        println("-->${describe(1L)}")
        println("-->${describe(321)}")
        println("-->${describe("abc")}")

        //- 4.for循环
        val items = listOf("a", "ca", "ac", "bb", "ab", "ba", "c")
        //for 循环可以对任何提供迭代器（iterator）的对象进⾏遍历,相当于foreach
        for (item in items)
            println("for-->$item")
        //如果你想要通过索引遍历⼀个数组或者⼀个 list：
        for (index in items.indices)
            println("for-->item at $index is ${items[index]}")
        //或者⽤库函数 withIndex ：
        for ((index, value) in items.withIndex()) {
            println("the element at $index is $value")
        }
        //可以⽤标签限制 break 或者continue：
        loop@ for (i in 1..100) {
            for (j in 1..100) {
                if (i + j == 200) break@loop
            }
        }
        //返回到标签: Kotlin 有函数字⾯量、局部函数和对象表达式。因此 Kotlin 的函数可以被嵌套。 标签限制的 return 允许我们从外层 函数返回
        fun foo() {
            listOf(1, 2, 3, 4, 5).forEach {
                if (it == 3) return // ⾮局部直接返回到 foo() 的调⽤者
                print(it)
            }
            println("this point is unreachable")
        }

        fun foo2() {
            listOf(1, 2, 3, 4, 5).forEach lit@{
                if (it == 3) return@lit // 局部返回到该 lambda 表达式的调⽤者，即 forEach 循环
                print(it)
            }
            print(" done with explicit label")
        }

        //通常情况下使⽤隐式标签更⽅便。 该标签与接受该 lambda 的函数同名
        fun foo3() {
            listOf(1, 2, 3, 4, 5).forEach {
                if (it == 3) return@forEach // 局部返回到该 lambda 表达式的调⽤者，即 forEach 循环
                print(it)
            }
            print(" done with implicit label")
        }

        //或者，我们⽤⼀个匿名函数替代 lambda 表达式。 匿名函数内部的 return 语句将从该匿名函数⾃⾝返回
        fun foo4() {
            listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
                if (value == 3) return // 局部返回到匿名函数的调⽤者，即 forEach 循环
                print(value)
            })
            print(" done with anonymous function")
        }

        // 请注意，前⽂三个⽰例中使⽤的局部返回类似于在常规循环中使⽤ continue。并没有 break 的直接等价形式，不过
        //可以通过增加另⼀层嵌套 lambda 表达式并从其中⾮局部返回来模拟：
        fun foo5() {
            run loop@{
                listOf(1, 2, 3, 4, 5).forEach {
                    if (it == 3) return@loop // 从传⼊ run 的 lambda 表达式⾮局部返回
                    print(it)
                }
            }
            print(" done with nested loop")
        }
        //当要返⼀个回值的时候，解析器优先选⽤标签限制的 return，即
        //return@a 1
        //意为“返回 1 到 @a ”，⽽不是“返回⼀个标签标注的表达式 (@a 1) ”。

        //- 5.while循环
        var index = 0
        while (index < items.size) {
            println("while-->item at $index is ${items[index]}")
            index++
        }
        var index2 = 0
        do {
            println("while-->item at $index2 is ${items[index2]}")
            index++
        } while (index2 < items.size)

        /**
         * 5. 可空值和null检测,详见printNums中
         */
        printNums(num, userName = null)

        /**
         * 6. 使用类型检测及自动类型转换
         */
        fun getStringLength(obj: Any): Int? {
            if (obj is String) {
                // `obj` 在该条件分支内自动转换成 `String`
                return obj.length
            }
            return null
        }

        val len = getStringLength(s1)
        println("$s1<--len-->$len")

        //类型别名:如果有⼀个在代码库中多次⽤到的函数类型或者带有类型参数的类型，
        // 那么最好为它定义⼀个类型别名：
//        typealias MouseClickHandler = (Any, MouseEvent) -> Unit
//        typealias PersonIndex = Map<String, Person>

        /**
         * 7. 使用区间（range）
         */
        //- 1.区间外
        num = 100
        if (num !in 0..10) {
            println("num 不在0～10范围内")
        }
        //- 2.区间内
        val max = 100
        if (num in 1..max + 1) {//闭区间:包含101
            println("num 在1～101范围内")
        }
        if (num in 1 until max) {//半开区间:不包含 100
            println("num 在1～99范围内")
        } else {
            println("num 不 在1～99范围内")
        }
        //for (i in 0..n - 1) { /*……*/ } // 不良
        //for (i in 0 until n) { /*……*/ } // 良好

        //- 3.区间迭代
        for (it in 1..10) {
            println("x = $it")
        }

        //- 4.数列迭代 (步长)
        for (y in 1..10 step 2)
            println("y = $y")
        for (z in 9 downTo 0 step 3)
            println("z = $z")

        /**
         * 8.使用集合
         *
         */
        for (item in items) {
            println("for-->$item")
        }
        when {
            "a" in items -> println("items 包含 a")
            "c" in items -> println("items 包含 c")
            "d" in items -> println("items 包含 d")
        }
        //使用 lambda 表达式来过滤(filter)和映射(map)集合
        //优先使⽤⾼阶函数（filter 、map 等）⽽不是循环
        items.filter { it.contains("a") }//过滤
            .sortedBy { it }//排序
            .map { "--" + it.toUpperCase() }//转换
            .forEach { println(it) }//遍历
        //过滤
        val nums = listOf(0, 1, 2, 3, 4)
        //1
        nums.filter { it -> it > 2 }
            .forEach { println(it) }
        //2
        nums.filter { it > 2 }
            .forEach { println(it) }

        //检测元素是否存在于集合中
        if ("aaa@qq.com" in items) {
            //todo
        }
        if ("bbb@qq.com" !in items) {
            //todo
        }

        //val创建的list/map表示只读
        val list = listOf(2, 4, 6, 8)
        val map = mapOf("name" to "ljy", "age" to 18, "isMan" to true)
        // map["name"]="abc"//对元素进行修改会在编辑时直接提示错误

        //遍历 map/pair型list
        for ((k, v) in map) {
            println("$k-->$v")//k,v可改为任意名字
        }

        //总是使⽤不可变集合接⼝（Collection , List , Set , Map ）来声明⽆需改变的集合
        //使⽤⼯⼚函数创建集合实例时，尽可能选⽤返回不可变集合类型的函数

        // 不良：使⽤可变集合类型作为⽆需改变的值
        fun validateValue(actualValue: String, allowedValues: HashSet<String>) {
            //todo
        }

        // 良好：使⽤不可变集合类型
        fun validateValue(actualValue: String, allowedValues: Set<String>) {
            //todo
        }
        // 不良：arrayListOf() 返回 ArrayList<T>，这是⼀个可变集合类型
        val allowedValues1 = arrayListOf("a", "b", "c")
        // 良好：listOf() 返回 List<T>
        val allowedValues2 = listOf("a", "b", "c")

        /**
         * 9.延迟属性
         *
         * 相当于：if(p==null) { p=1+2+3+4+5 }
         * 且是第一次用到时才加载
         */
        val p: Int by lazy {
            1 + 2 + 3 + 4 + 5
        }
        println("p --> $p")

        /**
         * 10.扩展函数
         * 放⼿去⽤扩展函数
         * 每当你有⼀个主要⽤于某个对象的函数时，可以考虑使其成为⼀个以该对象为接收者的扩展函数。
         * 为了尽量减少 API 污染，尽可能地限制扩展函数的可⻅性
         * 下例为给String类添加一个扩展函数add
         */
        fun String.add(s: String): String {
            return "$this$s"
        }

        println("abc".add("def"))

        /**
         * 11.创建单例
         */
        println(StrConfig.name)
        println(StrConfig.s)

        /**
         * 12 try/cache表达式
         */
        fun test(): Int {
            var result = try {
                12 / 0
            } catch (e: Exception) {
                -1
            }
            return result
        }

        println("result=${test()}")

        /**
         * 13 对一个对象实例调用多个方法(with)
         *
         */
        //1.1 创建一个类:见Person.kt
        //1.2 添加一个扩展函数
        fun Person.sayHi() {
            println("$name say: Hello World")
        }

        //2.创建类对象
        val person = Person("ljy", "123456@qq.com")
        //3.with调用一个对象对多个方法
        with(person)
        {
            val s = toString()
            println(s)
            hashCode()
            println(name)
            println(email)
            sayHi()
        }

        person.email = "aaa"
//        person.name="aaa"

        /**
         * 14 对于需要泛型信息的泛型函数的适宜形式
         */
        //1. java
        //  public final class Gson {
        // ......
        // public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException {
        // ......
        //2. kotlin
//        inline fun <reified T: Any> Gson.fromJson(json: JsonElement): T
//                = this.fromJson(json, T::class.java)

        /**
         * 15 使用可空布尔
         */
        val bol: Boolean? = null
        if (bol == true) {
            println("bol = true")
        } else {
            println("`bol` 是 false 或者 null ")
        }

        /**
         * 16 冒号
         *  类型和超类型之间的冒号前要有一个空格，而实例和类型之间的冒号前不要有空格
         *  详见下面对Bar和Bar2
         */

        /**
         * 17.TODO()：将代码标记为不完整
         * Kotlin 的标准库有⼀个 TODO() 函数，该函数总是抛出⼀个 NotImplementedError 。 其返回类型为 Nothing，
         * 因此⽆论预期类型是什么都可以使⽤它。 还有⼀个接受原因参数的重载：
         */
        fun testTODO(): BigDecimal = TODO("waiting for feedback from accounting")

        /**
         * 18.注解格式化
         */
        //注解通常放在单独的⾏上，在它们所依附的声明之前，并使⽤相同的缩进：
//        @Target(AnnotationTarget.PROPERTY)
//        annotation class JsonExclude
        //⽆参数的注解可以放在同⼀⾏：
//        @JsonExclude @JvmField
//        var x: String
        //⽆参数的单个注解可以与相应的声明放在同⼀⾏：
//        @Test fun foo() { /*……*/ }
        //⽂件注解: ⽂件注解位于⽂件注释（如果有的话）之后、package 语句之前，
        // 并且⽤⼀个空⽩⾏与 package 分开（为了强调其针 对⽂件⽽不是包）。

        ///** 授权许可、版权以及任何其他内容 */
        //@file:JvmName("FooBar")
        //
        //package foo.bar
    }

    interface Bar

    interface Bar2<out T : Any> : Bar {
        fun foo(a:Int): T
    }

    /**
     * 创建单例
     */
    object StrConfig {
        //经过const修饰的常量，才是java中理解的常量
        const val name = "Mr.L"
        var s = "str"
    }
}


